package com.lemon.cloud.admin.web;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.lemon.cloud.admin.dto.UserDTO;
import com.lemon.cloud.admin.entity.RoleOrg;
import com.lemon.cloud.admin.entity.SysUserAtt;
import com.lemon.cloud.admin.entity.UserRole;
import com.lemon.cloud.admin.service.*;
import com.lemon.cloud.admin.vo.UserInfoVO;
import com.lemon.cloud.admin.vo.UserVO;
import com.lemon.cloud.comm.constants.enums.DelFlagEnum;
import com.lemon.cloud.comm.constants.enums.MenuTypeEnum;
import com.lemon.cloud.comm.model.ResultCode;
import com.lemon.cloud.comm.model.ResultMsg;
import com.lemon.cloud.comm.po.SysMenu;
import com.lemon.cloud.comm.po.SysRole;
import com.lemon.cloud.comm.po.SysUser;
import com.lemon.cloud.datascope.utils.DataScopeUtils;
import com.lemon.cloud.idempotent.annotation.Idempotent;
import com.lemon.cloud.security.annotation.Inner;
import com.lemon.cloud.security.model.SecurityUser;
import com.lemon.cloud.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("user")
@Tag(name = "用户接口")
public class SysUserController {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysUserAttService sysUserAttService;

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private RoleOrgService roleOrgService;

    @GetMapping("/getByUsername")
    @Inner
    @Hidden
    ResultMsg<SysUser> getByUsername(@RequestParam(value = "username") String username) {
        return ResultMsg.resultSuccess(sysUserService.getUserByUsername(username));
    }

    @GetMapping(value = "/getByMobile")
    @Inner
    @Hidden
    ResultMsg<SysUser> getByMobile(@RequestParam(value = "mobile") String mobile) {
        return ResultMsg.resultSuccess(sysUserService.getByMobile(mobile));
    }

    @GetMapping("/getRolesByUserId")
    @Inner
    @Hidden
    ResultMsg<List<SysRole>> getRolesByUserId(@RequestParam(value = "sysUserId") Long sysUserId) {
        return ResultMsg.resultSuccess(roleService.getRolesByUserId(sysUserId));
    }

    /**
     * 当前用户详情
     *
     * @return
     */
    @Operation(
            summary = "当前用户详情",description = "当前用户详情",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = UserInfoVO.class))},useReturnTypeSchema = true)
            }
    )
    @GetMapping("/info")
    public ResultMsg<UserInfoVO> info() {
        String username = SecurityUtils.getUser().getUsername();
        SysUser user = sysUserService.getUserByUsername(username);
        if (user == null) {
            return ResultMsg.resultFail(ResultCode.SERVICE_EXCEPTION.getCode(), "用户不存在");
        }
        UserInfoVO vo = new UserInfoVO();
        vo.setSysUser(user);
        List<SysRole> roleList = roleService.getRolesByUserId(user.getId());
        vo.setRoles(roleList.stream().map(SysRole::getCode).toArray(String[]::new));
        List<SysMenu> permissionByRoles = Lists.newArrayList();
        for (SysRole r : roleList) {
            if (CollectionUtil.isNotEmpty(r.getPermissionList())) {
                permissionByRoles.addAll(r.getPermissionList());
            }
        }
        vo.setPermissions(permissionByRoles.stream()
                .filter(m -> MenuTypeEnum.BUTTON.getType().equals(m.getType()))
                .map(SysMenu::getPermission)
                .filter(StrUtil::isNotBlank)
                .toArray(String[]::new));
        return ResultMsg.resultSuccess(vo);
    }

    /**
     * 当前用户额外详情
     * @return
     */
    @Operation(
            summary = "当前用户额外详情",description = "当前用户额外详情",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = SysUserAtt.class))},useReturnTypeSchema = true)
            }
    )
    @GetMapping("/attInfo")
    public ResultMsg<SysUserAtt> attInfo() {
        SecurityUser user = SecurityUtils.getUser();
        SysUserAtt sysUserAtt = sysUserAttService.getById(user.getId());
        if (sysUserAtt==null){
            sysUserAtt = new SysUserAtt();
        }
        return ResultMsg.resultSuccess(sysUserAtt);
    }

    /**
     * 用户修改个人信息
     *
     * @return
     */
    @Operation(
            summary = "用户修改个人信息",description = "用户修改个人信息",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation")
            }
    )
    @PutMapping("edit")
    public ResultMsg<Boolean> editUser(@Parameter @Valid @RequestBody UserDTO userDto) {
        return ResultMsg.resultSuccess(sysUserService.editUser(userDto));
    }

    /**
     * 检测用户账户是否存在
     *
     * @param dto
     * @return
     */
    @Operation(
            summary = "检测用户账户是否存在",
            responses = {
                    @ApiResponse(responseCode = "200",description = "true：存在，false:不存在",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = Boolean.class))},useReturnTypeSchema = true)
            }
    )
    @Inner(false)
    @PostMapping("/check/exist")
    public ResultMsg<Boolean> exist(@Parameter @RequestBody UserDTO dto) {
        long count = sysUserService.count(new LambdaQueryWrapper<SysUser>()
                .eq(!StrUtil.isEmpty(dto.getUsername()), SysUser::getUsername, dto.getUsername())
                .eq(!StrUtil.isEmpty(dto.getMobile()), SysUser::getMobile, dto.getMobile())
        );
        if (count <= 0) {
            return ResultMsg.resultSuccess(false);
        }
        return ResultMsg.resultSuccess(true);
    }

    /**
     * 注册用户
     *
     * @param dto
     * @return
     */
    @Operation(
            summary = "注册用户",
            responses = {
                    @ApiResponse(responseCode = "200",description = "true：成功，false:注册不成功",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = Boolean.class))},useReturnTypeSchema = true)
            }
    )
    @Inner(false)
    @PostMapping("/register")
    @Idempotent(key = "admin:info:",eval = "#dto.mobile",expireTime = 10,delKey = true)
    public ResultMsg<Boolean> register(@Parameter @RequestBody @Valid UserDTO dto) {
        return sysUserService.register(dto);
    }


    /**
     * 分页查询用户
     *
     * @param page    参数集
     * @param userDTO 查询参数列表
     * @return 用户集合
     */
    @Operation(
            summary = "分页查询用户",description = "分页查询用户",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation",content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE,schema = @Schema(implementation = IPage.class))},useReturnTypeSchema = true)
            }
    )
    @GetMapping("/page")
    public ResultMsg<IPage<UserVO>> getUserPage(Page<UserVO> page, UserDTO userDTO) {
        return ResultMsg.resultSuccess(sysUserService.getUserByPage(page, userDTO));
    }

    /**
     * 修改用户角色和权限信息
     *
     * @return
     */
    @Operation(
            summary = "修改用户角色和权限信息",description = "修改用户角色和权限信息",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation")
            }
    )
    @PutMapping
    @PreAuthorize("hasAuthority('sys_user_edit')")
    public ResultMsg<Boolean> updateUser(@Parameter @Valid @RequestBody UserDTO userDto) {
        Assert.state(DataScopeUtils.isInDataScope(userDto.getOrg()), "操作的部门不在数据权限内");
        return ResultMsg.resultSuccess(sysUserService.updateUser(userDto));
    }

    /**
     * 删除用户
     *
     * @param id
     * @return
     */
    @Operation(
            summary = "删除用户",description = "删除用户",
            parameters = {@Parameter(name="id",description = "用户id",required = true,in = ParameterIn.PATH)},
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation")
            }
    )
    @DeleteMapping("/{id}")
    @PreAuthorize("hasAuthority('sys_user_del')")
    public ResultMsg<Boolean> deleteUser(@PathVariable("id") Long id) {
        dataScope(id);
        return ResultMsg.resultSuccess(sysUserService.update(new LambdaUpdateWrapper<SysUser>()
                .set(SysUser::getDelFlag, DelFlagEnum.DELETE.getValue())
                .eq(SysUser::getId, id)));
    }

    /**
     * 添加用户
     */
    @Operation(
            summary = "添加用户",description = "添加用户",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation")
            }
    )
    @PostMapping
    @PreAuthorize("hasAuthority('sys_user_add')")
    public ResultMsg<Boolean> addUser(@Parameter @Valid @RequestBody UserDTO userDto) {
        Assert.state(DataScopeUtils.isInDataScope(userDto.getOrg()), "添加的部门不在数据权限内");
        return ResultMsg.resultSuccess(sysUserService.saveUser(userDto));
    }

    /**
     * 强制下线
     */
    @Operation(
            summary = "强制下线",description = "强制下线",
            responses = {
                    @ApiResponse(responseCode = "200",description = "successful operation")
            }
    )
    @PostMapping("/forceOffline")
    @PreAuthorize("hasAnyAuthority('sys_token_del')")
    public ResultMsg<Boolean> forceOffline(@Parameter @RequestBody UserDTO userDto) {
        if (userDto.getId() == null || StrUtil.isEmpty(userDto.getClient())) {
            return ResultMsg.resultFail("参数不合法");
        }
        dataScope(userDto.getId());
        sysUserService.forceOffline(userDto.getId(), userDto.getClient());
        return ResultMsg.resultSuccess();
    }

    private void dataScope(Long id) {
        List<Long> roleList = userRoleService.list(new LambdaQueryWrapper<UserRole>()
                .eq(UserRole::getUserId, id))
                .stream().map(UserRole::getRoleId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(roleList)){
            return;
        }
        List<Long> org = roleOrgService.list(new LambdaQueryWrapper<RoleOrg>().in(RoleOrg::getRoleId, roleList)).stream().map(RoleOrg::getOrgId)
                .collect(Collectors.toList());
        Assert.state(DataScopeUtils.isInDataScope(org), "操作的部门不在数据权限内");
    }
}

